﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace OWLServer.owl.tipos
{
    /// <summary>
    /// Clase que representa un problema que se pueda dar en la creación de en una ontología.
    /// </summary>
    public class Problema
    {
        private TipoProblema tipo;
        private Individuo individuo1;
        private Individuo individuo2;
        private Elemento elementoImplicado1;
        private Elemento elementoImplicado2;
        private Elemento elementoImplicado3;
        private UnionClasesDisjuntas unionClasesDisjuntas;
        private int cardinalidad;

        /// <summary>
        /// Tipo del problema
        /// </summary>
        public virtual TipoProblema Tipo
        {
            get { return tipo; }
            set { tipo = value; }
        }

        /// <summary>
        /// Individuo 1 implicado en el problema
        /// </summary>
        public virtual Individuo Individuo1
        {
            get { return individuo1; }
            set { individuo1 = value; }
        }

        /// <summary>
        /// Individuo 2 implicado en el problema
        /// </summary>
        public virtual Individuo Individuo2
        {
            get { return individuo2; }
            set { individuo2 = value; }
        }
        
        /// <summary>
        /// Elemento 1 implicada en el problema
        /// </summary>
        public virtual Elemento ElementoImplicado1
        {
            get { return elementoImplicado1; }
            set { elementoImplicado1 = value; }
        }

        /// <summary>
        /// Elemento 2 implicada en el problema
        /// </summary>
        public virtual Elemento ElementoImplicado2
        {
            get { return elementoImplicado2; }
            set { elementoImplicado2 = value; }
        }

        /// <summary>
        /// Elemento 3 implicada en el problema
        /// </summary>
        public virtual Elemento ElementoImplicado3
        {
            get { return elementoImplicado3; }
            set { elementoImplicado3 = value; }
        }

        /// <summary>
        /// Cardinalidad asociada a las restricciones de cardinalidad
        /// </summary>
        public virtual int Cardinalidad
        {
            get { return cardinalidad; }
            set { cardinalidad = value; }
        }

        /// <summary>
        /// Union de clases disjuntas
        /// </summary>
        public virtual UnionClasesDisjuntas UnionClasesDisjuntas
        {
            get { return unionClasesDisjuntas; }
            set { unionClasesDisjuntas = value; }
        }

        /// <summary>
        /// Problema de contrucción de elementos de la ontología.
        /// </summary>
        /// <param name="individuo1">Individuo 1 implicado en el problema</param>
        /// <param name="individuo2">Individuo 2 implicado en el problema</param>
        /// <param name="tipo">Tipo de problema</param>
        /// <param name="elementoImplicado1">Elemento 1 implicada en el problema</param>
        /// <param name="elementoImplicado2">Elemento 2 implicada en el problema</param>
        public Problema(Individuo individuo1, Individuo individuo2, TipoProblema tipo, Elemento elementoImplicado1, Elemento elementoImplicado2)
        {
            Individuo1 = individuo1;
            Individuo2 = individuo2;
            Tipo = tipo;
            ElementoImplicado1 = elementoImplicado1;
            ElementoImplicado2 = elementoImplicado2;
        }

        /// <summary>
        /// Problema de contrucción de elementos de la ontología.
        /// </summary>
        /// <param name="individuo1">Individuo 1 implicado en el problema</param>
        /// <param name="individuo2">Individuo 2 implicado en el problema</param>
        /// <param name="tipo">Tipo de problema</param>
        /// <param name="elementoImplicado1">Elemento 1 implicada en el problema</param>
        public Problema(Individuo individuo1, Individuo individuo2, TipoProblema tipo, Elemento elementoImplicado)
        {
            Individuo1 = individuo1;
            Individuo2 = individuo2;
            Tipo = tipo;
            ElementoImplicado1 = elementoImplicado;
        }

        /// <summary>
        /// Problema de contrucción de elementos de la ontología.
        /// </summary>
        /// <param name="individuo">Individuo implicado en el problema</param>
        /// <param name="tipo">Tipo de problema</param>
        /// <param name="elementoImplicado1">Elemento 1 implicada en el problema</param>
        /// <param name="elementoImplicado2">Elemento 2 implicada en el problema</param>
        public Problema(Individuo individuo, TipoProblema tipo, Elemento elementoImplicado1, Elemento elementoImplicado2)
        {
            Individuo1 = individuo;
            Tipo = tipo;
            ElementoImplicado1 = elementoImplicado1;
            ElementoImplicado2 = elementoImplicado2;
        }

        /// <summary>
        /// Problema de contrucción de elementos de la ontología.
        /// </summary>
        /// <param name="individuo">Individuo implicado en el problema</param>
        /// <param name="tipo">Tipo de problema</param>
        /// <param name="elementoImplicado1">Elemento 1 implicada en el problema</param>
        /// <param name="unionClasesDisjuntas">Union de clases disjuntas implicada en el problema</param>
        public Problema(Individuo individuo, TipoProblema tipo, Elemento elementoImplicado1, UnionClasesDisjuntas unionClasesDisjuntas)
        {
            Individuo1 = individuo;
            Tipo = tipo;
            ElementoImplicado1 = elementoImplicado1;
            UnionClasesDisjuntas = unionClasesDisjuntas;
        }

        /// <summary>
        /// Problema de contrucción de elementos de la ontología.
        /// </summary>
        /// <param name="tipo">Tipo de problema</param>
        /// <param name="elementoImplicado1">Elemento 1 implicada en el problema</param>
        /// <param name="elementoImplicado2">Elemento 2 implicada en el problema</param>
        public Problema(TipoProblema tipo, Elemento elementoImplicado1, Elemento elementoImplicado2)
        {
            Tipo = tipo;
            ElementoImplicado1 = elementoImplicado1;
            ElementoImplicado2 = elementoImplicado2;
        }

        /// <summary>
        /// Problema de contrucción de elementos de la ontología.
        /// </summary>
        /// <param name="tipo">Tipo de problema</param>
        /// <param name="elementoImplicado1">Individuo implicado en el problema</param>
        public Problema(TipoProblema tipo, Individuo elementoImplicado1)
        {
            Tipo = tipo;
            Individuo1 = individuo1;
        }

        override public String ToString()
        {
            String cadena = "";

            switch (Tipo)
            {
                case TipoProblema.UNION_CLASES_DISJUNTAS:
                    foreach (Clase clase in UnionClasesDisjuntas.ElementosUnionClasesDisjuntas)
                    {
                        cadena = cadena + clase.Id + " - ";
                    }

                    cadena = "El individuo '" + Individuo1.Id + "' no pude ser de los tipos '" + cadena + "' porque son disjuntos con el " + ElementoImplicado1.Id +  ".";
                    break;
                case TipoProblema.CLASE_DISJUNTA:
                    cadena = "El individuo '" + Individuo1.Id + "' no pude ser de los tipos '" + ElementoImplicado1.Id + "' y '" + ElementoImplicado2.Id + "' porque son el primero es disjunto con el segundo.";
                    break;
                case TipoProblema.INDIVIDUO_IGUAL_Y_DIFERENTE:
                    cadena = "El individuo '" + ElementoImplicado1.Id + "' es igual y diferente, a la vez, con el individuo '" + ElementoImplicado2.Id + "'.";
                    break;
                case TipoProblema.PROPIEDAD_SUB_PROPIEDAD:
                    cadena = "La propiedad '" + ElementoImplicado1.Id + "' es subpropiedad de '" + ElementoImplicado2.Id + "' pero no tienen los mismos dominios y rangos.";
                    break;
                case TipoProblema.PROPIEDAD_INVERSA:
                    cadena = "Hay una propiedad '" + elementoImplicado1.Id + "' entre el individuo '" + individuo1.Id + "' y el individuo '" + individuo2.Id + "' y debería existir otra propiedad '" + elementoImplicado2.Id + "' entre el individuo '" + individuo2.Id + "' y el individuo '" + individuo1.Id + "', porque las primera propiedad tiene como inversa la segunda.";
                    break;
                case TipoProblema.PROPIEDAD_FUERA_RANGO:
                    cadena = "En la propiedad '" + elementoImplicado1.Id + "' del individuo '" + individuo1.Id + "' no puede tener como valor el individuo '" + individuo2.Id + "' porque no pernenece al rango de la propiedad.";
                    break;
                case TipoProblema.RESTRICCION_PROPIEDAD_FUERA_DOMINIO:
                    cadena = "Existe una restriccion en la clase '" + elementoImplicado1.Id + "' vinculada con la propiedad '" + elementoImplicado2.Id + "', donde dicha clase no pertenece dominio de la propiedad.";
                    break;
                case TipoProblema.RESTRICCION_PROPIEDAD_FUERA_RANGO:
                    cadena = "Existe una restriccion en la clase '" + elementoImplicado1.Id + "' vinculada con la propiedad '" + elementoImplicado2.Id + "', donde la clase '" + elementoImplicado3.Id + "' a la que hace referencia dicha propiedad no pertenece rango de la propiedad.";
                    break;
                case TipoProblema.RESTRICCION_TODOS_LOS_INDIVIDUOS_MISMO_TIPO:
                    cadena = "El individuo '" + Individuo1.Id + "' tiene una propiedad '" + ElementoImplicado1.Id + "' en la cual todos los individuos con los que se vincula tienen que ser de la clase '" + ElementoImplicado2.Id + "'";
                    break;
                case TipoProblema.RESTRICCION_ALGUN_INDIVIDUO_DE_UN_TIPO:
                    cadena = "El individuo '" + Individuo1.Id + "' tiene una propiedad '" + ElementoImplicado1.Id + "' en la cual algúnos de los individuos con los que se vincula tienen que ser de la clase '" + ElementoImplicado2.Id + "'";
                    break;
                case TipoProblema.RESTRICCION_CARDINALIDAD:
                    cadena = "El individuo '" + Individuo1.Id + "' tiene una propiedad '" + ElementoImplicado1.Id + "' en la cual debe de tener concramente " + Cardinalidad + " individuos.";
                    break;
                case TipoProblema.RESTRICCION_CARDINALIDAD_MAXIMA:
                    cadena = "El individuo '" + Individuo1.Id + "' tiene una propiedad '" + ElementoImplicado1.Id + "' en la cual debe de tener como máximo " + Cardinalidad + " individuos.";
                    break;
                case TipoProblema.RESTRICCION_CARDINALIDAD_MINIMA:
                    cadena = "El individuo '" + Individuo1.Id + "' tiene una propiedad '" + ElementoImplicado1.Id + "' en la cual debe de tener como mínimo " + Cardinalidad + " individuos.";
                    break;
                case TipoProblema.INDIVIDUO_DUPLICADO:
                    cadena = "El individuo '" + Individuo1.Id + "' está duplicado.";
                    break;
                default:
                    cadena = "Tipo problema en el Individuo '" + (individuo1 == null ? "" : individuo1.Id) + "'.";
                    break;
            }

            return cadena;
        }
    }

    public enum TipoProblema : int
    {
        CLASE_DISJUNTA,
        UNION_CLASES_DISJUNTAS,
        INDIVIDUO_IGUAL_Y_DIFERENTE,
        PROPIEDAD_SUB_PROPIEDAD,
        PROPIEDAD_INVERSA,
        PROPIEDAD_FUERA_RANGO,
        RESTRICCION_PROPIEDAD_FUERA_DOMINIO,
        RESTRICCION_PROPIEDAD_FUERA_RANGO,
        RESTRICCION_TODOS_LOS_INDIVIDUOS_MISMO_TIPO,
        RESTRICCION_ALGUN_INDIVIDUO_DE_UN_TIPO,
        RESTRICCION_CARDINALIDAD,
        RESTRICCION_CARDINALIDAD_MINIMA,
        RESTRICCION_CARDINALIDAD_MAXIMA,
        INDIVIDUO_DUPLICADO
    }
}
